package com.eece411.project.p2;

import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

public class Server{
	private final static int COMMAND_SIZE=1;

	/**
	 * Multithread socket server
	 * Source : http://www.tutorialspoint.com/javaexamples/net_multisoc.htm
	 */
	public static void main(String[] args) throws Exception {
		@SuppressWarnings("resource")
		// Create socket
		ServerSocket ssock = new ServerSocket(2048);
		// Set the routing system
		Routing.getInstance();
		System.out.println("Ready");
		// var for the get of the command
	    byte[] command = new byte[COMMAND_SIZE];
	    int totalBytesRcvd=0;
	    
	    // Main loop for the client/server connection
		while (!ES.getInstance().isTerminated()) {
			try{
				// Loop to accept client
				Socket sock = ssock.accept();
				long startTime = System.currentTimeMillis();
				totalBytesRcvd=0;
				// Read until the expected length of the header or timeout
				while (totalBytesRcvd < command.length && ((System.currentTimeMillis()-startTime)<500)) {
					int bytesRcvd;
					if ((bytesRcvd = sock.getInputStream().read(command, totalBytesRcvd,  
							command.length - totalBytesRcvd)) == -1)
						throw new SocketException("Connection close prematurely");
					totalBytesRcvd += bytesRcvd;
				}
				if (((System.currentTimeMillis()-startTime)<500)){
					// Split according to the protocol
					// Switch for each command
		            if(((command[0] & 0xFF) == 0x01)||((command[0] & 0xFF) == 0x03)||((command[0] & 0xFF) == 0x02)||((command[0] & 0xFF) == 0x20)){
		            	// If client command check the number of active connection then make a request thread
		            	if(Routing.getInstance().connectClient()){
		            		ES.getInstance().execute(new ThreadSck(command[0],sock,startTime));
		            	} else {
							sock.getOutputStream().write((byte) 3);
							System.out.println("--- System Overload");
							sock.close();
						}
		            } else if(((command[0] & 0xFF) == 0x04)){
		            	// Shutdown the KVStore
						System.out.println("--- System Shutdown");
						ES.getInstance().shutdown();
						sock.getOutputStream().write((byte) 0);
						sock.close();
					} else if(((command[0] & 0xFF) == 0x21)||((command[0] & 0xFF) == 0x23)){
						// If server connection create a thread to service it
						ES.getInstance().execute(new ThreadSckServer(command[0],sock,startTime));
					} else {
						// Command not found -> error 5
						sock.getOutputStream().write((byte) 5);
						System.out.println("--- Command not found");
						sock.close();
					}
				} else {
					// Timeout for client ->  Error 21
					sock.getOutputStream().write((byte) 21);
					System.out.println("--- Kick client");
					sock.close();
				}
			} catch (SocketException e){
				System.out.println("--- Error in get key");
			}
		}
	}
}
